Foreword
Mad-Pascal (MP) is a 32-bit Turbo Pascal compiler for Atari 8-Bit and other MOS 6502 CPU-based computers. By design, it is compatible with the Free Pascal Compiler (FPC) (the -MDelphi switch should be active). This means the possibility of obtaining executable code for Atari 8-bit, Windows, and every other platform for which FPC exists. Mad-Pascal is not a port of FPC. It has been written based on SUB-Pascal (2009) and XD-Pascal (2010), the author of which is Vasiliy Tereshkov.

Mad-Pascal uses 64KB of primary memory. The class TMemoryStream provides access to extended memory. A program that works on Atari 8-Bit might have problems on Windows and other platforms if, for example, the pointers have not been initialized with the address of a variable. Writing via an uninitialized pointer results in an attempt to write to the address 0x0 and causes a memory protection fault.

The strengths of Mad-Pascal include the fast and convenient possibility of including inline assembly. A program using inline ASM only works on platforms with MOS 6502 CPU.

Variable allocation is static. There is no dynamic memory management. Parameters are passed to functions by value, variable, or constant.

The available features are:

If Case For While Repeat statements
Compound statements
Label Goto statements
Arithmetic and boolean operators
Procedures and functions with up to 8 parameters. The returned value of a function is assigned to a predefined RESULT variable
Static local variables
Primitive data types, all types except the ShortReal/Real type, are compatible. Pointers are dereferenced as pointers to Word:
Cardinal Word Byte Boolean
String PChar Char
Integer SmallInt ShortInt
Pointer File Text
ShortReal Real fixed-point
Float Single
Float16
One-dimensional and Two-dimensional arrays (with zero lower bound) of any primitive type. Arrays are treated as pointers to their origins (like in C) and can be passed to subroutines as parameters
Predefined type string [N], which is equivalent to array [0..N] of Char
Type aliases.
Records
Objects
Separate program modules
Separate library modules
Recursion
Folder Structure
In the folder Mad-Pascal, the following files and subfolders are required:

  MP\
    mp.exe
    base\
      atari\
      c4p\
      c64\
      common\
      neo\
      raw\
      runtime\    
      rtl_default.asm
      rtl6502_a8.asm
      rtl6502_c4p.asm
      rtl6502_c64.asm
      rtl6502_neo.asm
      rtl6502_raw.asm
    blibs\
    dlibs\
    include\
    lib\
    src\
    targets\
    wblibs\
Compiling
To compile the sources of Mad-Pascal use the Free Pascal Compiler (FPC), which can be downloaded from freepascal.org.

Launch the installer and choose the folder for the installation of FPC. It is crucial not to use the exclamation mark ! or other nonstandard characters in the folder name. If it fails to compile any file, it is probably the fault of a nonstandard pathname. The command line launching the compilation may look as follows (letter case in parameter names matters):

fpc -Mdelphi -v -O3 mp.pas
-Mdelphi allows for Delphi format file compilation
-v shows all error and warning diagnostics
-O3 performs code optimization
Libraries
LIB
BLIBS
WLIBS


Comments
In Mad-Pascal // is used to mark a one-line comment and { } or (* *) mark a multiline comment.

// this is a comment
inc(a); // this also is a comment

(* comment *)

(*

  comment

*)

{ this
  is
  a comment
}
Reserved identifiers
reserved commands
absolute           and                 array              asm               assembler
begin              case                const              constructor       div
do                 downto              else               end               exports
external           file                for                forward           function
if                 implementation      in                 interrupt         interface
length             library             main               mod               not               
object             of                  or                 overload          pascal
procedure          program             record             register          repeat
shl                shr                 string             text              textfile
then               to                  type               unit              until
uses               var                 while              xor
reserved constants
pi
true
false
nil
eol
nan
infinity
neginfinity
Expressions
Numbers
decimal notation
-100
-2437325
1743
hexadecimal notation
$100
$e430
$000001
binary notation
%0001001010
%000000001
%001000
ATASCII code notation
'a'
'fds'
'W'
#65#32#65
#$9b
Operators
arithmetic
+   Addition
-   Subtraction
*   Multiplication
/   Division
DIV Integer division
MOD Remainder
bitwise
NOT Bitwise negation (unary)
AND Bitwise and
OR  Bitwise or
XOR Bitwise xor
SHL Bitwise shift to the left
SHR Bitwise shift to the right
logical
NOT logical negation (unary)
AND logical and
OR  logical or
XOR logical xor
relational
=   Equal
<>  Not equal
<   Less than
>   Greater than
<=  Less than or equal
>=  Greater than or equal
Compiler directives
Compiler directives are of form::

{$directive parameters}
{$list_of_switch_directives}
A directive is a comment differentiated from a regular comment by the first $ character.

CONDITIONAL
{$IFDEF label}
{$IFNDEF label}
{$ELSE}
{$ENDIF}
{$DEFINE label}
{$UNDEF label}
{$define test}

const
  {$ifdef test}
  a=1;
  {$else}
  a=2;
  {$endif}
Inside ASM blocks access to defined $DEFINE directives is only possible through MAIN.@DEFINES.label.

$BIN2CSV
Includes the contents of a external binary file, into the source code, like a CSV text.

For example, if a binary file contains the bytes $1E, $1F, $20, the directive will generates the string 30, 31, 32.

This directive can be used to initialize arrays.

  //Initialize with a binary content
  AAA: array[3] of byte = ({$BIN2CSV data.bin});
$CODEALIGN PROC = value
The $CODEALIGN PROC directive allows the generated result code to be aligned to the VALUE bytes of the memory page. A .ALIGN VALUE code is inserted before each PROCEDURE, FUNCTION block. To disable alignment, set {$CODEALIGN PROC = 0}.

$CODEALIGN LOOP = value
The $CODEALIGN LOOP directive allows the generated result code to be aligned to the VALUE bytes of the memory page. A .ALIGN VALUE code is inserted before each FOR, WHILE, REPEAT iteration instruction. To disable alignment, set {$CODEALIGN LOOP = 0}.

$CODEALIGN LINK = value
The $CODEALIGN LINK directive allows the generated result code to be aligned to the VALUE bytes of the memory page. Before each {$LINK filename} directive, the .ALIGN VALUE code is inserted. To disable alignment, set {$CODEALIGN LINK = 0}.

$DEFINE
BASICOFF
{$DEFINE BASICOFF}
Additional code block that shutdown ATARI BASIC.

ROMOFF
{$DEFINE ROMOFF}
We gain access to the memory under the ROM: $C000..$CFFF, $D800..$FFFF.

The character set from ROM $E000..$E3FF is rewritten to the same address in RAM, the interrupt handler NMI, IRQ is installed. The operating system works normally, you can call the procedures contained in it from the ASM using the macro m@call.

WARNING:
When the ANTIC Display List program is placed under the ROM, each key press will trigger an IRQ interrupt that handles the keyboard.

The ANTIC program will be interfered with by ROM - RAM switching, in case we use the Display List interrupt (DLI) the stack may be damaged and the system may crash.

NOROMFONT
{$DEFINE NOROMFONT}
Supplement for {$DEFINE ROMOFF}, prevents rewriting of character set from ROM to RAM

$ERROR
{$ERROR user_defined}
Generate error message.

$F, $FASTMUL
{$fastmul page}   // fastmul at page*256
{$f $70}          // fastmul at $7000
Alternative procedures for fast multiplication of the BYTE SHORTINT WORD SMALLINT SHORTREAL types. The procedures occupy 2KB and are located starting from the address PAGE*256.

$I+, $I-, IOCHECK
{$I+}
{$I-}
{i+}  IOCHECK ON  default
{i-}  IOCHECK OFF
For {$i+} in case of I/O transmission errors RESET REWRITE BLOCKREAD BLOCKWRITE CLOSE the ran program is stopped and an error diagnostic ERROR xxx is generated. Disabling IOCHECK {$i-} is of use for file existence checking, for example:

function FileExists(name: TString): Boolean;
var f: file;
begin

  {$I-}     // io check off
  Assign (f, name);
  Reset (f);
  Result:=(IoResult<128) and (length(name)>0);
  Close (f);
  {$I+}     // io check on

end;
In PROCEDURE and FUNCTION blocks, the IOCHECK directive is of local scope, after finishing the compilation of such block the previous value of IOCHECK, defined outside of such block, is restored.

$I, $INCLUDE
%DATE%
{$INCLUDE %DATE%}
{$I %DATE%}
Directive parameter %DATE% for inclusion of a string with current compilation date.

%TIME%
{$INCLUDE %TIME%}
{$I %TIME%}
Directive parameter %TIME% for inclusion of a string with current compilation time.

FILENAME
{$INCLUDE filename}
{$I filename}
Directive parameter FILENAME to attach the text contained in the file.

$INFO
{$INFO user_defined}
Generate info message.

$LIBRARYPATH
{$LIBRARYPATH path1;path2;...}
Directive to indicate additional search paths for libraries unit.

$LINK
{$LINK filename}
The {$link filename} directive allows you to include and integrate code and procedures assembled in Mad Pascal program.

For more on linking the assembler to Mad Pascal, see Assembler Insertions.

$MACRO
{$MACRO ON}
{$MACRO OFF}
{$MACRO+}
{$MACRO-}
The {$macro } directive enables/disables the ability to define macros, is required by FPC, in Mad-Pascal it is retained for compatibility purposes only.

$OPTIMIZATION
LOOPUNROLL
{$OPTIMIZATION loopunroll}
The $OPTIMIZATION directive with the LOOPUNROLL parameter allows you to unroll FOR loops (the parameters of such a loop must be constants):

{$OPTIMIZATION loopunroll}

 for i:=0 to 11 do tab[i]:=i*2;

{$OPTIMIZATION noloopunroll}
NOLOOPUNROLL
{$OPTIMIZATION noloopunroll}
The NOLOOPUNROLL parameter disables the FOR loop unroll.

$R, $RESOURCE
{$R filename}
{$RESOURCE filename}

RCLABEL RCTYPE RCFILE [PAR0 PAR1 PAR2 PAR3 PAR4 PAR5 PAR6 PAR7]
Directive to load a resource file. A resource file is a text file, each of its successive lines should consist of three fields separated by a whitespace character: RCLABEL, the label (its declaration can be included in the program), RCTYPE, the resource type and RCFILE, the file location.The base\<platform>\resource.asm file contains macros to support the different types of RCTYPE resources:

RCDATA
Any data type.

EXTMEM
Any data type loaded into PORTB secondary memory, loading address determined by RCLABEL.

RCASM
An assembly file that will be attached and assembled.

DOSFILE
Atari DOS header file, the loading address of such a file should be the same as RCLABEL.

RELOC
A relocatable file in MadAssembler format, the file will be relocated to the address indicated by RCLABEL.

RMT
Raster Music Tracker module file, the file will be relocated to the address indicated by RCLABEL.

MPT
The Music ProTracker module file, the file will be relocated to the indicated address RCLABEL.

CMC
Chaos Music Composer module file, the file will be relocated to the address indicated by RCLABEL.

RMTPLAY
Player for the RMT module, with the *.FEAT file passed as the RCFILE and the player mode 0..3 passed as the PAR0.

    0 => compile RMTplayer for 4 tracks mono
    1 => compile RMTplayer for 8 tracks stereo
    2 => compile RMTplayer for 4 tracks stereo L1 R2 R3 L4
    3 => compile RMTplayer for 4 tracks stereo L1 L2 R3 R4
MPTPLAY
Player for MPT module.

CMCPLAY
Player for CMC module.

XBMP
Windows Bitmap file (8 BitsPerPixel) loaded into VBXE memory to the indicated address RCLABEL from PAR0 color index in VBXE color palette no. 1.

Example:

bmp1  RCDATA   'pic.mic'
msx   MPT      'porazka.mpt'
play  RMTPLAY  'modul.feat' 1
bmp   XBMP     'pic.bmp' 80
$WARNING
{$WARNING user_defined}
Generate warning message.

--- types
Ordinal types
Type	Range	Size in bytes
BYTE	0 .. 255	1
SHORTINT	-128 .. 127	1
WORD	0 .. 65535	2
SMALLINT	-32768 .. 32767	2
CARDINAL	0 .. 4294967295	4
LONGWORD	0 .. 4294967295	4
DWORD	0 .. 4294967295	4
UINT32	0 .. 4294967295	4
INTEGER	-2147483648 .. 2147483647	4
LONGINT	-2147483648 .. 2147483647	4


Boolean types
Type	Ord(True)	Size in bytes
BOOLEAN	1	1


Enumeration types
The enumeration type in Mad-Pascal has been implemented in its basic form, i.e.:

Type
  Days = (monday,tuesday,wednesday,thursday,friday,
          saturday,sunday);

  Joy = (right_down = 5, right_up, right, left_down = 9, left_up, left, down = 13, up, none);
The enumeration type is stored only in the memory of the Mad-Pascal compiler, no information about the enumeration type fields will be stored in the result file. It is permissible to use the ORD, SIZEOF and casts on the enumeration type.

var
   d: Days;

   d:=friday;
   writeln(ord(d));
   writeln(ord(sunday));
   writeln(sizeof(days));
   writeln(sizeof(monday));

   d:=days(20);

   case d of
    sunday: writeln('sunday');
   end;
Currently, the Mad-Pascal compiler does not check the correctness of enumeration types for IF ELSE operations.

Real types
Type	Range	Size in bytes
SHORTREAL (Q8.8)	-128..127	2
REAL (Q24.8)	-8388608..8388607	4
SINGLE (IEEE-754)	1.5E-45 .. 3.4E38	4
FLOAT (IEEE-754)	1.5E-45 .. 3.4E38	4
FLOAT16 (IEEE-754)	65504 .. -65504	2

Conversion of FLOAT SINGLE to INTEGER type is only available in the range INTEGER. The INTEGER type will not allow to present the maximum value 3.4E38 of FLOAT SINGLE type.

Char types
Type	Range	Size in bytes
CHAR	ATASCII (0 .. 255)	1
STRING	1 .. 255	256
PCHAR	0 .. 65535	2

The STRING is represented as an array with a possible maximum size [0..255]. The first byte of such an array [0] is the string length from the range 0..255. The actual character string begins from the byte [1..].

A pointer to the CHAR type represents the PCHAR string. The terminator of the PCHAR string is the #0 character.

It is allowed to use additional characters after the final apostrophe, such as *, ~.

The character * means a string in the inverse; the tilde ~ means a string in ANTIC codes.

Another way to modify the output characters is to use the system variable TextAttr, each character output to the screen is increased by the value TextAttr (default = 0).

a: string = 'Atari'*;         // a character string in the inverse
b: string = 'Spectrum'~;      // a character string in ANTIC codes
c: char = 'X'~*;              // a character in inverted ANTIC codes
Pointers
Type	Range	Size in bytes
POINTER	0 .. 65535	2

Indicators in Mad-Pascal can be typed and without a specific type, e.g.:

a: ^word;         // a typed pointer to a word
b: pointer;       // an untyped pointer
An uninitialized pointer will most often have the address of $0000, you should make sure that before you use it, you will have initialized it with the address of the appropriate variable, e.g.:

a := @tmp;         // pointer A is assigned the address of the TMP variable
If you don't do this, if you run such a program on a PC, you may cause a memory protection fault Access Violation.

Increasing the pointer using INC increases it by the size of the type it indicates. Decreasing the pointer using DEC reduces it by the size of the type it indicates. If the type is unspecified, the default step for increase/decrease is 1.

For pointers, relation operations =, <>, <, <=, >, >=, and arithmetic operations + and - are allowed.

Using a pointer, we can cast a variable to another type:

var
   s: single;
   d: cardinal;

begin

 s := 3.14;

 d:=PCardinal(@s)^; // d = $4048F5C3

end;
Static arrays
Tables in Mad-Pascal are only static, one-dimensional or two-dimensional with an initial index equal to 0, e.g:

var tb: array [0..100] of word;
var tb2: array [0..15, 0..31] of Boolean;
For an initial index other than zero, an error Error Array lower bound is not zero is generated.

In the memory the array is represented by the pointer POINTER, the pointer is the address of the array in memory (WORD). The quickest way to refer to the table from an ASM block is to use the prefix ADR, e.g.:

asm
{ lda adr.tb,y   ; direct reference to the TB array
  lda tb         ; reference to the TB array pointer
};
The compiler generates code for the arrays depending on their declaration:

when the number of bytes does not exceed 256 bytes
array [0..255] of byte
array [0..127] of word
array [0..63] of cardinal
When the number of bytes occupied by the array does not exceed 256 bytes, the fastest code referring directly to the address of the array (prefix ADR.) is generated without the pointer. It is not possible to change the address for such an array.

ldy #118
lda adr.tb,y
when the number of elements of an array is 1
array [0..0] of type
When the number of elements of an array is 1 it is treated specifically. The code generated refers to the array through the pointer. It is possible to set a new address for such a table.

lda TB
add I
tay
lda TB+1
adc #$00
sta bp+1
lda (bp),y
when the number of bytes exceeds 256 bytes
array [0..255+1] of byte
array [0..127+1] of word
array [0..63+1] of cardinal
When the number of bytes occupied by the array exceeds 256 bytes, the generated code refers to the array via an pointer. When the number of bytes occupied by the array exceeds 256 bytes, the generated code refers to the array through a pointer.

lda TB
add I
tay
lda TB+1
adc #$00
sta bp+1
lda (bp),y
Record types
In the memory the record is represented by a pointer POINTER.

type
    TPoint = record x,y: byte end;
var px: TPoint;
By default, records in Mad-Pascal are of type PACKED. The total size of the record fields is limited to 256 bytes.

If you want to maintain FPC compatibility, you should additionally precede the word record with the word packed.

Without this, the size of the memory that the record takes varies, it occupies less memory on MOS 6502 target, potentially several bytes more on Windows.

type
    TPoint = packed record x,y: byte end;

    var px: TPoint;
Access to record fields from the assembly:

mwa px bp2
ldy #px.x-DATAORIGIN
lda (bp2),y
Table of records
Mad-Pascal only supports arrays of record pointers.

    type
        TPoint = record x,y: byte end;    

    var 
        tab: array [0..3] of ^TPoint;
Such an array must be instantiated with the corresponding record addresses, by default all fields of such an array are zeroed at the beginning.

The first way to instantiate an array of record indicators:

    var
       a1,a2,a3,a4: TPoint;       

    begin
     tab[0] := @a1;
     tab[1] := @a2;
     tab[2] := @a3;
     tab[3] := @a4;   
    end.
Second way:

    begin
     GetMem(tab[0], sizeof(TPoint));
     GetMem(tab[1], sizeof(TPoint));
     GetMem(tab[2], sizeof(TPoint));
     GetMem(tab[3], sizeof(TPoint));
    end.
Access record fields from such an array:

  writeln(tab[1].x);
  writeln(tab[1].y);
Object types
Objects are records with additional methods. In the memory, the object is represented by a pointer POINTER.

type
    TRMT = Object

    player: pointer;
    modul: pointer;

    procedure Init(a: byte); assembler;
    procedure Play; assembler;
    procedure Stop; assembler;

    end;
It is possible to use the CONSTRUCTOR and DESTRUCTOR procedures in objects. Such procedures can only be called manually.

Procedural
In memory, procedural type variables are represented by the POINTER type.

type
    tprc = procedure (a: byte; c: word);
    tfun = function (a:smallint; x: single): byte;

var
    fn: function (a,b,c: byte): word;
For the procedural type, procedures/functions with arguments require the STDCALL modifier, which will force the use of the program stack.

var
   fn: function (a,b: word): word;

function test(a,b,c,d: word): word; stdcall;
begin

end;

begin

fn := @test;

fn(1,2);

end;
For procedures with arguments instead of the STDCALL modifier, the REGISTER modifier is allowed, provided there are up to three arguments.

var
   prc: procedure (a,b: word);

procedure test(a,b,c: cardinal); register;
begin

// a -> EDX
// b -> ECX
// c -> EAX

end;

begin

prc := @test;

prc(3,6);

end;
When no arguments are passed to the procedure/function, the use of modifier is not necessary.

File types
The FILE type represents the file handle and defines the record size.

type
  ftype = array [0..63] of cardinal;

var
  f: file;               // default record =128 bytes
  f: file of byte;       // 1 byte record
  f: file of ftype;      // 256 byte record (ftype = 64 * 4)
In the Atari 8-Bit memory, the FILE holder is represented by a pointer POINTER to an array of structure (size 12 bytes):

.struct s@file
pfname   .word      ; pointer to string with filename
record   .word      ; record size
chanel   .byte      ; channel *$10
eof      .byte      ; EOF status
buffer   .word      ; load/write buffer
nrecord  .word      ; number of records for load/write
numread  .word      ; pointer to variable, length of loaded data
.ends
For procedures and functions, the FILEtype can only be passed as a variable VAR.

Untyped
 procedure Something (var Data);
 procedure Something (const Data);
Failure to specify the type of the parameter means that only the address of the parameter without the type designation will be passed to the procedure/function.

This is equivalent to the following C/C++ declaration:

 void Something(void* Data);
Inside a procedure/function with an unsigned parameter, if an unsigned parameter is used in an expression or a value must be assigned to it, always use type casting.

var x: word;

procedure test(var a);
begin

  writeln(PWord(@a)^);  // = 95

  PWord(@a)^ := 11;

end;

begin

  x:=95;

  test(x);              // = 11

end.

--- constants

Ordinary constants
The character = is used for the CONST constant declarations. The use of operators:

+ - * / not and or div mod ord chr sizeof pi

is possible in the constant expression to compute the constant value at compile time. Ordinary constants have a variable type and the compiler will convert them to the required type at when they are used.

const
  e = 2.7182818;       { Real type constant }
  a = 2;               { Ordinal BYTE type constant }
  c = '4';             { Character type constant }
  s = 'atari';         { String type constant }
  sc = chr(32);
  ls = SizeOf(cardinal);
Typed constants
You can also specify the fixed type of a constant explicitly.

const
  f : single = 3.14;
  x : word = 5;
  pbox : array [0..1] of word = (12,10);
The syntax for specifying the initialization in CONST arrays is the same as VAR arrays. See section Initialization for details.


--- variables

VAR
The word VAR begins the variable declaration section.

var
    label: type;
    label: type = value;
var
    a: word;
    b: byte = 1;
    c: Boolean = true;

    s: string = 'Atari';

    tb: array [0..3] of byte = (0,1,2,3);
VOLATILE
The VOLATILE modifier marks a variable as so-called volatile. Marking it as VOLATILE disables optimization of the resulting code for that variable. Every read access to the variable will read from the memory location and will not re-use values that were already read by previous instructions. This is useful for hardware registers whose values may change with each successive read and for variables that are modified in parallel by other code the is not known to the compiler, for example by interrupt handlers.

var
  [volatile] joy   : byte absolute $ff08;
  pio              : byte absolute $fd30;

begin
  repeat
    pio := $ff;
    joy := 2;
    if (joy xor $ff) = 1 then writeln('UP');
  until false;
end.
ABSOLUTE
The ABSOLUTE modifier allows you to set the address in memory for VAR variables.

var
   a: byte absolute $0600;
   tb: array [0..255] of byte absolute $a000;

   tab: array [0..3] of byte;
   v: integer absolute tab;

   procedure test(var buf);
   var ptr: PByte absolute buf;
REGISTER
The REGISTER modifier sets the memory address for VAR variables on the zero page (a maximum of 16 bytes can be allocated).

var
   a: byte register;
   c: integer register;
WARNING:
The same 16-byte area of the zero page is used by the compiler allocating its EDX ECX EAX registers there, so using the REGISTER modifier is not possible when a procedure or function also uses REGISTER.

procedure test(a,b,c: integer); register;
Initialization
Mad Pascal initializes all global and local variables once upon program start to the equivalent of zero or the explicitly specifed values. Note that this is different from the FPC behavior where only global variables are guranteed to be initialized. Because initialization only takes place upon program start and because it is not guranteed in FPC you should always explicitly assign values to local variables when a procedure or functions is entered. The syntax for specifying the initialization values in CONST and VAR declarations is identical. After the word specifying the data type, place the = character and the initial value.

Array initialization
After the word specifying the data type of the array, place the = character and the subsequent elements of the array between the round brackets ( val0, val1, ... ) :

const
   pbox : array [0..1] of word = (12,10);

var
   pbox : array [0..1] of word = (12,10);
In the case of a two-dimensional array:

   pbox : array [0..1, 0..1] of word = ( (12,10) , (1,6) );
We can instantiate an array of type CHAR by STRING:

   pbox : array [0..4] of char = 'Hello';
It is possible to initialize an array without specifying its size using square brackets [ ] :

   pbox : array of char = ['H', 'e', 'l', 'l', 'o'];

   pbox : array of word = [1,2,3,4,5];

   pbox : array of char = 'Hello';        // char arry without square brackets [ ]
It is possible to initialize an array of type BYTE from a binary file, using the directive {$bin2csv filename} :

   tb: array of byte = [ {$bin2csv filename} ];

   tb: array [0..11] of byte = ( 1,2,3, {$bin2csv filename} );

--- instructions

Conditional
case of else
Currently, Mad Pascal only accepts types with a length of 1 byte for the CASE variable: SHORTINT BYTE CHAR BOOLEAN.

case a of               // for a variable A of type CHAR
  'A'..'Z': begin end;
  '0'..'9': begin end;
  '+','*': begin end;
end;
if then else
IF conditional instructions can be nested. This is used for more complex conditions.

Iterative
for to downto do
FOR variable := { initial value } TO { final value } DO { instructions to execute }
FOR variable := { final value } DOWNTO { initial value } DO { instructions to execute }
This instruction is used to organize calculations which are performed a predetermined number of times. The control variable shall be an identifier of the ordinal type and both expressions shall be consistent in terms of assignment with the control variable type. During the TO loop execution, the control variable is assigned the subsequent value in the given type, in the DOWNTO loop, the preceding one. It is prohibited to "manually" change the value of a control variable. In case of such an attempt, Mad-Pascal signal an error Illegal assignment to for-loop variable.

The compiler makes sure that there is no endless loop so that you can use such a loop without a doubt:

for i:=0 to 255 do writeln(i);    // for a variable I of type BYTE
for in do
    FOR variable IN array DO { instructions to execute }
    FOR variable IN 'string literal' DO { instructions to execute }
The FOR IN DO construct allows for faster reading of array elements or text constants.

    var
    days : array [0..6] of string =
    ('poniedzialek', 'wtorek', 'sroda' ,'czwartek', 'piatek', 'sobota', 'niedziela');

    a: string;

    begin
      for a in days do writeln(a);
while do
while { condition } do { instructions to execute }
This construct is used to organize calculations that will be performed as long as the expression after the word WHILE is true. Such a loop may not be executed even once.

while BlitterBusy do;   // waiting for the VBXE blitter to finish
Limitations for WHILE instructions:

while i<=255 do inc(i); // endless loop if I is of type BYTE
repeat until
repeat
  { instructions to execute }
until { termination condition }
This statement cyclically executes other statements between REPEAT and UNTIL until the expression after UNTIL takes the value of TRUE.

The effect of the REPEAT loop is very similar to that of the WHILE loop. This loop can also be performed a huge number of times. The only difference is that in the REPEAT loop the end condition is only checked after the instruction is executed. This means that the REPEAT loop will always be done at least once. Only after this iteration will the program check if the loop can be terminated. In the case of the WHILE loop, the condition is checked immediately before it is executed, which may result in the loop never being executed.

i:=0;
repeat
  inc(i);
until i=0;      // the loop will repeat 256 times


--- Programs, units, libraries

UNIT
The UNIT modules come only in the form of source .pas files, they cannot be compiled separately.

The UNIT modules consist of sections:

INTERFACE wymagana
IMPLEMENTATION wymagana
INITIALIZATION opcjonalna.
{
  Example UNIT
}
unit Unit1;

interface

uses // List of unit dependencies goes here...

// Interface section goes here

implementation

uses // List of unit dependencies goes here...

// Implementation of procedures, and functions goes here...

initialization

// Unit initialization code goes here...

end.
Example:

unit test;

interface

type  TUInt24 =
  record
    byte0: byte;
    byte1: byte;
    byte2: byte;
  end;

const
  LoRes = 1;
  MedRes = 2;
  HiRes = 3;

  procedure Print(a: string);

implementation

uses test2;

procedure Print(a: string);
begin

  writeln(a);

end;

end.
LIBRARY
The library header is required.

   library name [: address];
It is possible to specify the compilation address after the colon character :, this is equivalent to the command-line switch -code address.

The structure of the library is similar to the unit module, program program.

{
  Example LIBRARY
}
library lib1;

uses // List of unit dependencies goes here...

// Implementation of procedures, and functions goes here...


// exported subroutine(s), variable(s)

exports

idents, ... ;

// optional library initialization code goes here...

begin

end.
By default, functions and procedures declared and implemented in the library are not available to a programmer who wants to use the library.

To make functions or procedures from the library available, they must be exported in the exports clause.

Functions, procedures and other identifiers are exported with the exact names specified in the exports clause.

To use libraries in UNIT modules or PROGRAM program, they must first be compiled and assembled, the Mad Assembler-a -hm switch must be active.

mads.exe library.pas -hm -xi:<Mad_Pascal_path>\base
We cannot place .pas files with library source code in the uses clause.

To use the identifiers exported in LIBRARY we use the EXTERNAL modifier.

USES
The uses clause imports identifiers from unit modules.

Each Mad-Pascal unit - program, unit, or library - can have a maximum of one uses clause per section, which must appear immediately after the section headers.

Section headers are interface, implementation in unit modules. There are no explicit section headers in program and library, so the uses clause appears immediately after the program, library header.

    uses crt, sysutils, atari;
The SYSTEM module cannot be in this list, because it is always loaded by the compiler by default.

The order in which modules appear is important because it determines the order in which they are initialized. Modules are initialized in the same order in which they appear in the uses clause.

Identifiers are searched for in reverse order, that is, when the compiler looks for an identifier, it looks for it first in the last module in the uses clause, then in the penultimate one, and so on. This is important when two or more modules in the uses clause declare the same identifier.

uses graph, vbxe;
In both GRAPH and VBXE modules there is a SetColor and Line procedure, for the aforementioned example references to these procedures will be made by the VBXE module,

uses vbxe, graph;
references to these procedures will be made by the GRAPH module.

We can also directly refer to the identifier from a specific module, such as:

    vbxe.Line
    graph.Line
    vbxe.SetColor
    graph.SetColor
The compiler will look for source versions of all modules listed in the uses clause based on the path from which the mp.exe compiler was run.

Using the IN keyword, we can override the automatic module search mechanism.

    uses unita in '..\unita.pas';
The unita module is searched for in the parent directory of the current compiler working directory. You can add a {$UNITPATH ..} directive to ensure that the module is found no matter where the current compiler working directory is.

When the compiler looks for module files, it adds the .pas extension to the module name.

$LIBRARYPATH
{$LIBRARYPATH path1; path2; ...}
The $LIBRARYPATH directive allows you to indicate additional search paths for UNIT modules declared by uses.

$UNITPATH
{$UNITPATH path1; path2; ...}
The $UNITPATH directive allows you to indicate additional search paths for UNIT modules declared by uses.


--- Procedures, functions, modifiers

Procedure
Mad-Pascal allows up to 8 parameters to be transferred to the procedure. There are three ways to pass parameters - by value, constant CONST and variable VAR. It is possible to use the OVERLOAD modifier to overload procedures.

Available procedure modifiers: OVERLOAD ASSEMBLER FORWARD KEEP REGISTER INTERRUPT PASCAL.

Procedure parameters are read and evaluated from right to left tests\tests-medium\function_valuation_of_arguments.pas

It is possible to recurse procedures, provided that the procedure parameters will be passed by value and will be of a simple - ordinal type. The record or pointer type will not be properly allocated in memory.

Function
Mad-Pascal allows you to transfer up to 8 parameters to the function. There are three ways to pass parameters - by value, constant CONST and variable VAR. We return the result of the function by assigning it to the function name or using the automatically declared RESULT variable, e.g:

function add(a,b: word): cardinal;
begin
  Result := a+b;
end;

function mul(a,b: word): cardinal;
begin
  mul := a*b;
end;
Available function modifiers: OVERLOAD ASSEMBLER KEEP FORWARD REGISTER INTERRUPT PASCAL

The modifier INTERRUPT is not recommended for functions.

Function parameters are read and evaluated from right to left tests\tests-medium\function_valuation_of_arguments.pas

It is possible to recurse functions, provided that the function parameters will be passed by value and will be of a simple - ordinal type. The record or pointer type will not be properly allocated in memory.

Modifiers
assembler
The procedures/functions marked by ASSEMBLER can only consist of an ASM block.

The compiler does not analyze the syntax of such blocks, treats them as a comment, possible errors are caught only during the assembly phase.

WARNING
It is required to maintain the state of the X CPU6502 register, which is used to operate the Mad-Pascal software stack.

procedure color(a: byte); assembler;
asm
{   mva a 712
};
end;
overload
Overloaded procedures/functions are recognized by the parameter list.

procedure sum(var i: integer; a,b: integer); overload;
begin
  i := a+b;
end;

procedure sum(var i: integer; a,b,c: integer); overload;
begin
  i := a+b+c;
end;

function fsum(a,b: word): cardinal; assembler; overload;
asm
{
  adw a b result
};
end;

function fsum(a,b: real): real; overload;
begin
  Result := a+b;
end;
forward
If you want the procedure/function to be declared after its first call, use the FORWARD modifier.

procedure name [(formal-parameter-list)]; forward;

...
...
...

procedure name;
begin
end;
keep
Normally unused procedure/function are excluded from the compiled code to minimize the code size. The KEEP modifier forces a procedure/function to remain in the compiled code regardless of whether its used or not. The modifier is required if the usage is inside an ASM block or a relocateable object file linked with $LINK.

register
Using REGISTER modifier causes the first three formal parameters of the procedure/function to be placed on the zero page, in 32-bit general-purpose registers EDX, ECX, EAX respectively.

procedure name (a,b,c: cardinal); register;

// a = edx
// b = ecx
// c = eax
interrupt
Procedures/Functions marked by INTERRUPT end with RTI instruction instead of the standard RTS instructon.

Regardless of whether such procedure/function is called in the program, the compiler always generates code for it.

It is recommended to use the ASM block for such procedure/function, otherwise the Mad Pascal software stack will be destroyed, which may lead to unstable program operation, including computer crashes. At the beginning of the procedure/function marked by INTERRUPT, the programmer must take care to keep the CPU registers A X Y, at the output to restore such registers, the compiler only inserts the final RTI command.

procedure dli; interrupt;
asm
{   pha

    lda #$c8
    sta wsync
    sta $d01a

    pla
};
end;             // the RTI instruction gets inserted automatically
pascal
Using the PASCAL modifier will cause procedure/function to be treated as recursive. By default, the compiler automatically detects recursion, but there may be situations where this is not possible.

Example samples/math/evaluate.pas

stdcall
Using the STDCALL modifier will force parameters to be passed to the procedure/function through the program stack. By default, the compiler tries to pass parameters through variables, without involving the program stack.

inline
The procedure, function is turned into a Mad-Assembler macro, getting rid of calls involving the JSR and RTS commands.

It is not possible to use recursion for such procedures/functions.


--- macros
Macros
Mad-Pascal allows you to use macros, just like FPC, except that macros are always enabled.

 {$macro on}
 {$macro off}
 {$macro+}
 {$macro-} 
The {$macro on} directive is required by FPC, in Mad-Pascal it is retained for compatibility purposes only.

Defining a macro
{$define label := expression}

{$define label(par0, par1 ... par7) := expression}
For a definition to be recognized as a macro, the assignment symbol := must occur after the label name and any (par0..par7) parameter list.

{$define new_proc :=

procedure test;
begin

 writeln('ok');

end;
}


  new_proc


begin

 test;

end.
{$define sum_xi

 :=

 x:=x+i;
 }

begin

 sum_xi;

end;
{$define WIDTH := 80}
{$define LEN   :=   ( WIDTH + 10 )}

var a: byte;

begin

 a := len * 20;

end.
Macros with parameters are supported by Mad-Pascal but not by FPC, keep this in mind if you intend to test code on other hardware platforms.

{$define SIGN_MASK := $8000}
{$define SIGNED_INF_VALUE(x) := ((x and SIGN_MASK) or $7C00)}

var a: byte = 11;

begin

 writeln( SIGNED_INF_VALUE(a shl 15) );

end.


--- assembler inlining

ASM
The compiler allows two syntaxes for inline assembler blocks: The ASM block, with { } brackets as for a comment and the standard one without brackets. The syntax of the code inside an assembler block is not verified by the compiler. This is done only by Mad-Assembler during the assembly of the *.a65 output file.

WARNING: The MOS 6502 CPU register X is used to operate the Mad-Pascal software stack. Therefore an assembler block must restore the original value of X at the end of the block, if the register is modified by the block.

ASM
  lda #10
  sta 712
END;
ASM
{  lda #10
   sta 712
};
procedure name; assembler;
asm
  lda #10
  sta 712
end;
procedure name; assembler;
asm
{
  lda #10
  sta 712
};
end;
$LINK
{$link filename}
The compiler directive {$link filename} allows you to link a relocatable object file from Mad-Assembler to a compiled Mad-Pascal program.

    .reloc

.extrn edx .dword

.extrn  print .proc (.dword edx) .var

.public prc


.proc   prc (.dword a .dword b .dword c) .var

.var a,b,c .dword

    print a
    print b
    print c

    rts

.endp
In the above example, we use the PRINT procedure, which is defined in Mad-Pascal.

uses crt;


procedure prc(a,b,c: integer); external;


procedure print(value: dword); keep; register;
begin

 writeln(value);

end;


{$link test.obx}    // link PRC procedure


begin

 prc(11, 347, 321785);

 repeat until keypressed;

end.
From the relocatable object files we have access to Mad-Pascal procedures but only to those marked with the modifier REGISTER, i.e. those whose parameters are passed through the program registers EDX, ECX, EAX (we are limited to a maximum of three parameters).

Mad-Pascal, on the other hand, has access to procedures from the linked assembler file, whose parameters are passed through variables, modifier .VAR.

.proc   prc (.dword a .dword b .dword c) .var
In Mad-Assembler relocatable program, we need an additional declaration of the external symbols EDX, ECX, EAX.

.extrn edx, ecx, eax .dword
The Mad-Pascal procedure itself, which we want to access from the ASM block, is declared as an external procedure with parameters denoting program registers EDX, ECX, EAX.

For more information on the REGISTER modifier and the order in which parameters are allocated in program registers, see Procedures and functions.

.extrn  print .proc (.dword edx) .var
We will access the PRC procedure from the Mad-Pascal level by making it public via the .PUBLIC assembler directive.

.public prc
After assembling our sample relocatable assembler program TEST.ASM, we get the file TEST.OBX, which we can link to the Mad-Pascal program with the {$LINK} directive.

--- Resources files

Resource files
Syntax of RC files
The RC files are plain text files. They contain a list of resources to be included in the compiled file. The basic syntax element looks as follows:

RCLABEL      RCTYPE     RCFILE      [PAR0, PAR1, PAR2, PAR3, PAR4, PAR5, PAR6, PAR7]
The contents of a RC file may include comments, preceded by a ';' or '#' character. An example of a RC file:

; this is a MPT player
mpt_player  MPTPLAY

# this is a MPT modul
mpt_modul   MPT 'porazka.mpt'
The resource type specifies the format of the file to be included.

Type	Info
RCDATA	Any data type, e.g.:
label RCDATA 'filename'
label RCDATA 'filename' OFFSET
EXTMEM	Any data type loaded into PORTB secondary memory, loading address determined by RCLABEL.
RCASM	The assembler file that will be included and assembled.
DOSFILE	File with Atari DOS header, the loading address of such a file should be identical to RCLABEL.
RELOC	Relocatable file in Mad-Assembler format, the file will be relocated to the indicated RCLABEL address.
RMT	The Raster Music Tracker-a module file, the file will be relocated to the indicated RCLABEL address.
MPT	The Music ProTracker-a module file, the file will be relocated to the indicated RCLABEL address.
CMC	The Chaos Music Composer-a module file, the file will be relocated to the indicated RCLABEL address.
SAPR	SAP-R data file, the file will be relocated to the indicated RCLABEL address.
RMTPLAY	Player for RMT module, specify *.FEAT file as RCFILE and additionally PAR0 player mode 0..3:
0 => compile RMTplayer for 4 tracks mono
1 => compile RMTplayer for 8 tracks stereo
2 => compile RMTplayer for 4 tracks stereo L1 R2 R3 L4
3 => compile RMTplayer for 4 tracks stereo L1 L2 R3 R4
SAPRPLAY	Player SAP-R LZSS, no need to specify file name RCFILE, address RCLABEL only from the beginning of the page.
MPTPLAY	Player for MPT module, no need to specify RCFILE file name.
CMCPLAY	Player for CMC module, no need to specify RCFILE file name.
XBMP	Windows Bitmap file (8 BitsPerPixel) loaded into VBXE memory at the indicated RCLABEL address from color index PAR0 in VBXE** color palette #1
 

Ability to load resources under ROM
    CMC             RAM / ROM
    CMCPLAY         RAM / ROM
    DOSFILE         RAM / ROM
    EXTMEM
    MPT             RAM / ROM
    MPTPLAY         RAM / ROM
    RCASM           RAM / ROM
    RCDATA          RAM / ROM
    RELOC           RAM
    RMT             RAM / ROM
    RMTPLAY         RAM
    XBMP
    SAPR            RAM / ROM
    SAPRPLAY        RAM / ROM
Including an RC file in the application
Insert a compiler directive in the program source code (e.g., at the beginning of the implementation section):

{$R myresources.rc}
In addition, specify in the program code the value for the RCLABEL labels of the corresponding resources, e.g.:

const

    mpt_player = $8000;

    mpt_modul = $9000;
The inclusion of the RC file occurs when the program is compiled.

If the resource address points to an address under ROM ($C000..$FFFF) then ANTIC is disabled. At program startup, write the appropriate value to the DMACTL registry. to turn the image back on.

Access to Resources
Resources are placed at the indicated RCLABEL addresses in memory. The only exception is the RCDATA resource type for which it is possible to omit the RCLABEL definition from the program code.

In the absence of a RCLABEL definition, the resource is included in the compiled program, accessed via the GetResourceHandle routine.

GetResourceHandle(pointer, 'rclabel');
The GetResourceHandle procedure sets the value of the POINTER for the resource 'RCLABEL'.


--- file operations

File operations
FILE
var f: file;
TEXT
var f: text;            // TEXT
    g: textfile;        // TEXTFILE alternatively
ASSIGN
Example of channel opening for S: device (screen) to output characters in GRAPHICS 1, GRAPHICS 2 mode

var scr: text;
    s: string = 'color COLOR ' + #155 + 'COLOR '* + 'color '*;

begin

 assign(scr, 'S:');      // before InitGraph
 rewrite(scr);           // before InitGraph

 InitGraph(2);           // Graphics 2

 GotoXY(1,6);

 write(scr, s);

 close(scr);

end.
RESET
var t: text;

 reset(t);          // for reading a text file, no additional parameter with record size
var f: file;

 reset(t, 1);       // for reading a binary file (record = 1)
If no record length is specified for the binary file FILE, the default value =128 will be taken

REWRITE
var t: text;

 rewrite(t);        // for writing a text file, no additional parameter with record size
var f: file;

 rewrite(f, 1);     // for writing a binary file (record = 1)
If no record length is specified for the binary file FILE, the default value =128 will be taken

APPEND
var
 t: text;

begin

 assign(t, 'D:TEXT.TXT');
 append(t);

 writeln(t, 'ATARI');

 writeln(t, 'C64');

 write(t, 'Amstrad');

 close(t);
BLOCKREAD
var f: file;
    pnt: pointer;

begin

 pnt:=pointer(dpeek(88));

 assign(f, 'D:FILENAME');
 reset(f, 1);
 blockread(f, pnt^, 8);
 close(f);

end.
var f: file;
    buf: array [0..0] of byte;

begin

 buf:=pointer(dpeek(88));

 assign(f, 'D:FILENAME');
 reset(f, 1);

 blockread(f, buf, 8);
 close(f);

end.
BLOCKWRITE
var f: file;
    buf: array [0..0] of byte ABSOLUTE $bc40;

begin

 assign(f, 'D:FILENAME');
 rewrite(f, 1);

 blockwrite(f, buf, 40*24);
 close(f);

end.